import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import java.io.File
import java.lang.reflect.ParameterizedType
import java.net.URL
import java.util.*

//class TrickyKotlin6<T : Any /* try to make this reified! */>() {
//    fun classOrSuperClassOf(anyGetter: () -> Any) = false
//}

typealias TrickyKotlin6<T> = Array<T>

inline fun <reified T> TrickyKotlin6() = arrayOf<T>()

fun Array<*>.classOrSuperClassOf(anyGetter: () -> Any): Boolean = run {
    val returnType = (anyGetter.javaClass.genericInterfaces[0] as ParameterizedType).actualTypeArguments[0]
    val clazz: Class<*> = (if (returnType is ParameterizedType) returnType.rawType else returnType) as Class<*>
    this.javaClass.componentType.isAssignableFrom(clazz)
}

class TrickyKotlin6Test {

    @Test
    fun testCase() {
//        assertTrue(TrickyKotlin6<String>().classOrSuperClassOf { throw RuntimeException() })
        assertTrue("",TrickyKotlin6<String>().classOrSuperClassOf { "" })
        assertTrue(TrickyKotlin6<CharSequence>().classOrSuperClassOf { "" })
        assertTrue(TrickyKotlin6<Comparable<String>>().classOrSuperClassOf { "" })
        assertTrue(TrickyKotlin6<Int>().classOrSuperClassOf { 2333 })
        val num = TrickyKotlin6<Number>()
        assertTrue(num.classOrSuperClassOf { 2333 })
        assertTrue(TrickyKotlin6<Long>().classOrSuperClassOf { 6666L })
        assertTrue(num.classOrSuperClassOf { 6666L })
        assertTrue(TrickyKotlin6<File>().classOrSuperClassOf { File("") })
        assertTrue(TrickyKotlin6<URL>().classOrSuperClassOf { URL("http://ice1000.org") })
        assertTrue(TrickyKotlin6<Collection<String>>().classOrSuperClassOf { listOf("") })
    }

    @Test
    fun finalTestCase() {
        assertTrue(TrickyKotlin6<File>().classOrSuperClassOf { object : File("") {} })
        assertTrue(TrickyKotlin6<Comparable<File>>().classOrSuperClassOf { File("") })
        assertTrue(TrickyKotlin6<Collection<String>>().classOrSuperClassOf { listOf("") })
        assertTrue(TrickyKotlin6<Comparable<File>>().classOrSuperClassOf { File("") })
        assertTrue(TrickyKotlin6<Unit>().classOrSuperClassOf { while (true) println("You're doing this Kata the wrong way!") })
        assertTrue(TrickyKotlin6<Unit>().classOrSuperClassOf(this::finalTestCase))
        assertTrue(TrickyKotlin6<Boolean>().classOrSuperClassOf { System.currentTimeMillis() == System.currentTimeMillis() })
        assertTrue(TrickyKotlin6<(Int) -> Int>().classOrSuperClassOf { { it: Int -> it + 1 } })
        assertTrue(TrickyKotlin6<(Boolean) -> Boolean>().classOrSuperClassOf { { it: Boolean -> !it } })
        assertTrue(TrickyKotlin6<TrickyKotlin6<Unit>>().classOrSuperClassOf { TrickyKotlin6<Unit>() })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { object : File("") {} })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { File("") })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { listOf("") })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { File("") })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { while (true) println("You're doing this Kata the wrong way!") })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf(this::finalTestCase))
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { System.currentTimeMillis() == System.currentTimeMillis() })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { { it: Int -> it + 1 } })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { { it: Boolean -> !it } })
        assertTrue(TrickyKotlin6<Any>().classOrSuperClassOf { TrickyKotlin6<Unit>() })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { object : File("") {} })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { File("") })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { listOf("") })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { File("") })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { while (true) println("You're doing this Kata the wrong way!") })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf(this::finalTestCase))
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { System.currentTimeMillis() == System.currentTimeMillis() })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { { it: Int -> it + 1 } })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { { it: Boolean -> !it } })
        assertFalse(TrickyKotlin6<String>().classOrSuperClassOf { TrickyKotlin6<Unit>() })
        assertFalse(TrickyKotlin6<File>().classOrSuperClassOf { "" })
        assertFalse(TrickyKotlin6<File>().classOrSuperClassOf { 2333 })
        val num = TrickyKotlin6<Class<*>>()
        assertFalse(num.classOrSuperClassOf { 2333 })
        assertFalse(TrickyKotlin6<Class<*>>().classOrSuperClassOf { 6666L })
        assertFalse(num.classOrSuperClassOf { 6666L })
        assertFalse(TrickyKotlin6<Class<*>>().classOrSuperClassOf { URL("http://ice1000.org") })
        assertFalse(TrickyKotlin6<LinkedList<String>>().classOrSuperClassOf { listOf("") })
        assertFalse(TrickyKotlin6<Class<*>>().classOrSuperClassOf { File("") })
    }
}